package com.cold.legendary.bprocess.db.repository;

import com.alibaba.fastjson.JSON;
import com.cold.legendary.bprocess.common.constance.BErrorCodeEnum;
import com.cold.legendary.bprocess.common.constance.CommonConstances;
import com.cold.legendary.bprocess.common.utils.BAssertUtil;
import com.cold.legendary.bprocess.context.run.BContext;
import com.cold.legendary.bprocess.db.enums.BizStatusEnum;
import com.cold.legendary.bprocess.db.enums.PointRunStatusEnum;
import com.cold.legendary.bprocess.db.mapper.TbProcessRequestMapper;
import com.cold.legendary.bprocess.db.model.TbProcessRequest;
import com.cold.legendary.bprocess.db.model.TbProcessRequestExample;
import com.cold.legendary.bprocess.db.model.base.PageParamsDto;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

/**
 * @author cold
 * @since 2023/3/8
 */
@Slf4j
@Service
public class ProcessRequestRepository {
    @Resource
    private TbProcessRequestMapper tbProcessRequestMapper;

    /**
     * 根据主键查询流程请求记录
     * @param requestId 流程请求id
     * @return 返回流程记录对象
     */
    public TbProcessRequest queryTbProcessRequest(String requestId) {
        BAssertUtil.notNull(requestId, BErrorCodeEnum.DB_PARAMS_ERROR);
        return tbProcessRequestMapper.selectByPrimaryKey(requestId);
    }

    /**
     * 查询流程请求记录
     * @param bizId 业务id
     * @param merchantId 商户号
     * @param processId 流程id
     * @return 流程记录
     */

    public TbProcessRequest queryTbProcessRequest(String bizId, String merchantId, String processId) {
        BAssertUtil.notBlank(bizId, BErrorCodeEnum.DB_PARAMS_ERROR);
        BAssertUtil.notBlank(merchantId, BErrorCodeEnum.DB_PARAMS_ERROR);
        BAssertUtil.notBlank(processId, BErrorCodeEnum.DB_PARAMS_ERROR);
        TbProcessRequestExample example = new TbProcessRequestExample();
        example.or()
                .andBizIdEqualTo(bizId)
                .andMerchantIdEqualTo(merchantId)
                .andProcessIdEqualTo(processId)
                .andIsDeletedEqualTo(CommonConstances.N);
        example.setOrderByClause(" create_time desc ");
        List<TbProcessRequest> tbProcessRequests = tbProcessRequestMapper.selectByExample(example);
        if (CollectionUtils.isEmpty(tbProcessRequests)) {
            return null;
        }
        if (tbProcessRequests.size() > 1) {
            log.error("查询到多条流程请求记录!请排查,默认返回最新一条!bizId={}, merchantId{}", bizId, merchantId);
        }
        return tbProcessRequests.get(0);
    }

    /**
     * 根据场景查询流程请求记录
     *
     * @param bizId
     * @param merchantId
     * @param bizScene
     * @return
     */
//    @Deprecated
//    public TbProcessRequest queryTbProcessRequest(String bizId, String merchantId, String bizScene) {
//        BAssertUtil.notBlank(bizId, BErrorCodeEnum.DB_PARAMS_ERROR);
//        BAssertUtil.notBlank(merchantId, BErrorCodeEnum.DB_PARAMS_ERROR);
//        BAssertUtil.notNull(bizScene, BErrorCodeEnum.DB_PARAMS_ERROR);
//
//        TbProcessRequestExample example = new TbProcessRequestExample();
//        example.createCriteria()
//                .andBizIdEqualTo(bizId)
//                .andMerchantIdEqualTo(merchantId)
//                .andBizSceneEqualTo(bizScene)
//                .andIsDeletedEqualTo(CommonConstances.N);
//        example.setOrderByClause(" create_time desc ");
//        List<TbProcessRequest> tbProcessRequests = tbProcessRequestRepository.selectByExample(example);
//        if (CollectionUtils.isEmpty(tbProcessRequests)) {
//            return null;
//        }
//        if (tbProcessRequests.size() > 1) {
//            log.error("查询到多条流程请求记录!请排查,默认返回最新一条!bizId={}, merchantId{}", bizId, merchantId);
//        }
//        return tbProcessRequests.get(0);
//    }


//    public List<TbProcessRequest> queryTbProcessRequests(String bizId, String merchantId, List<String> bizScenes) {
//        AssertUtil.notBlank(bizId, "数据库参数不合法");
//        AssertUtil.notBlank(merchantId, "数据库参数不合法");
//        AssertUtil.notEmpty(bizScenes, "数据库参数不合法");
//
//        Example example = new Example(TbProcessRequest.class);
//        example.createCriteria()
//                .andEqualTo("bizId", bizId)
//                .andEqualTo("merchantId", merchantId)
//                .andIn("bizScene", bizScenes)
//                .andEqualTo("isDeleted", "N");
//        example.orderBy(" order by create_time desc ");
//        return tbProcessRequestMapper.selectByExample(example);
//    }

    /**
     * 查询失败的流程请求记录
     * @param curPage 当前页码
     * @param pageSize 分页条数
     * @param agoDays 提前天数
     * @return 流程记录列表
     */
    public List<TbProcessRequest> queryErrorTbProcessRequestByPage(Integer curPage, Integer pageSize, Integer agoDays) {
        BAssertUtil.notNull(curPage, BErrorCodeEnum.DB_PARAMS_ERROR);
        BAssertUtil.notNull(pageSize, BErrorCodeEnum.DB_PARAMS_ERROR);

        Date fromDate = DateUtils.addDays(new Date(), -1 * agoDays);
        TbProcessRequestExample example = new TbProcessRequestExample();
        example.or()
                .andPointRunStatusEqualTo(PointRunStatusEnum.ERROR.getCode())
                .andCreateTimeGreaterThanOrEqualTo(fromDate)
                .andIsDeletedEqualTo(CommonConstances.N);
        example.setOrderByClause(" request_id asc ");
        example.setPageParamsDto(new PageParamsDto(curPage, pageSize));

        return tbProcessRequestMapper.selectByExample(example);
    }


    /**
     * 初始化流程请求记录
     * @param tbProcessRequest 流程请求记录
     * @return 流程主键id
     */
    public String initTbProcessRequest(TbProcessRequest tbProcessRequest) {
        BAssertUtil.notNull(tbProcessRequest, BErrorCodeEnum.DB_PARAMS_ERROR);
        BAssertUtil.notBlank(tbProcessRequest.getBizId(), BErrorCodeEnum.DB_PARAMS_ERROR);
        BAssertUtil.notBlank(tbProcessRequest.getMerchantId(), BErrorCodeEnum.DB_PARAMS_ERROR);
//        BAssertUtil.notBlank(tbProcessRequest.getBizScene(), BErrorCodeEnum.DB_PARAMS_ERROR);
        BAssertUtil.notBlank(tbProcessRequest.getPointId(), BErrorCodeEnum.DB_PARAMS_ERROR);
//        BAssertUtil.notBlank(tbProcessRequest.getUserId(), BErrorCodeEnum.DB_PARAMS_ERROR);

        tbProcessRequest.setPointRunStatus(PointRunStatusEnum.PROCESSING.getCode());
        tbProcessRequest.setPointRunMsg(CommonConstances.TEXT_INIT);
        tbProcessRequest.setCreateTime(new Date());
        tbProcessRequest.setUpdateTime(new Date());
        tbProcessRequest.setIsDeleted(CommonConstances.N);
        int result = tbProcessRequestMapper.insertSelective(tbProcessRequest);
        BAssertUtil.isTrue(result > 0, BErrorCodeEnum.DB_OPERATOR_ERROR);
        return tbProcessRequest.getRequestId();
    }


    /**
     * 更新流程请求记录
     * @param requestId 流程主键id
     * @param curPointId 当前节点
     * @param updateProcessRequest 更新数据
     */
    public void updateTbProcessRequest(String requestId, String curPointId, TbProcessRequest updateProcessRequest) {
        BAssertUtil.notBlank(requestId, BErrorCodeEnum.DB_PARAMS_ERROR);
        BAssertUtil.notBlank(curPointId, BErrorCodeEnum.DB_PARAMS_ERROR);
        BAssertUtil.notNull(updateProcessRequest, BErrorCodeEnum.DB_PARAMS_ERROR);

        updateProcessRequest.setUpdateTime(new Date());
        updateProcessRequest.setIsDeleted("N");

        TbProcessRequestExample example = new TbProcessRequestExample();
        example.createCriteria()
                .andRequestIdEqualTo(requestId)
                .andPointIdEqualTo(curPointId)
                .andIsDeletedEqualTo(CommonConstances.N);
        int result = tbProcessRequestMapper.updateByExampleSelective(updateProcessRequest, example);
        Assert.isTrue(result > 0, "数据库操作失败");
    }


    /**
     * 结束流程
     * @param requestId 主键id
     * @param curPointId 当前节点id
     * @param bizStatusEnum 业务状态
     * @param remark 备注
     * @param bContext 上下文
     */
    public void updateToFinish(String requestId, String curPointId, BizStatusEnum bizStatusEnum, String remark, BContext bContext) {
        BAssertUtil.notBlank(requestId, BErrorCodeEnum.DB_PARAMS_ERROR);
        BAssertUtil.notBlank(curPointId, BErrorCodeEnum.DB_PARAMS_ERROR);

        TbProcessRequest updateProcessRequest = new TbProcessRequest();
        updateProcessRequest.setRequestId(requestId);
        updateProcessRequest.setPointRunStatus(PointRunStatusEnum.FINISH.getCode());
        updateProcessRequest.setUpdateTime(new Date());
        updateProcessRequest.setRemark(remark);
        updateProcessRequest.setBizRefId(bContext.getBizRefId());
        updateProcessRequest.setRunContext(JSON.toJSONString(bContext));
        if (null != bizStatusEnum) {
            updateProcessRequest.setBizStatus(bizStatusEnum.getCode());
        }

        TbProcessRequestExample example = new TbProcessRequestExample();
        example.createCriteria()
                .andRequestIdEqualTo(requestId)
                .andPointIdEqualTo(curPointId)
                .andIsDeletedEqualTo(CommonConstances.N);

        int result = tbProcessRequestMapper.updateByPrimaryKeySelective(updateProcessRequest);
        Assert.isTrue(result > 0, "数据库操作失败");
    }

    /**
     * 等待流程
     * @param updateProcessRequest 更新对象
     * @param curPointId 当前节点id
     */
    public void updateToWaiting(TbProcessRequest updateProcessRequest, String curPointId) {

        BAssertUtil.notNull(updateProcessRequest, BErrorCodeEnum.DB_PARAMS_ERROR);
        BAssertUtil.notNull(updateProcessRequest.getRequestId(), BErrorCodeEnum.DB_PARAMS_ERROR);
        BAssertUtil.notBlank(curPointId, BErrorCodeEnum.DB_PARAMS_ERROR);

        updateProcessRequest.setPointRunStatus(PointRunStatusEnum.WAITING.getCode());
        updateProcessRequest.setUpdateTime(new Date());
        updateProcessRequest.setIsDeleted(CommonConstances.N);

        TbProcessRequestExample example = new TbProcessRequestExample();
        example.createCriteria()
                .andRequestIdEqualTo(updateProcessRequest.getRequestId())
                .andPointIdEqualTo(curPointId)
                .andPointRunStatusNotEqualTo(PointRunStatusEnum.FINISH.getCode())
                .andIsDeletedEqualTo(CommonConstances.N);

        int result = tbProcessRequestMapper.updateByExampleSelective(updateProcessRequest, example);
        Assert.isTrue(result > 0, "数据库操作失败");
    }


    /**
     * 继续流程
     * @param updateProcessRequest 更新对象
     * @param curPointId 当前节点id
     */
    public void updateForContinue(TbProcessRequest updateProcessRequest, String curPointId) {

        BAssertUtil.notNull(updateProcessRequest, BErrorCodeEnum.DB_PARAMS_ERROR);
        BAssertUtil.notBlank(updateProcessRequest.getRequestId(), BErrorCodeEnum.DB_PARAMS_ERROR);
        BAssertUtil.notBlank(curPointId, BErrorCodeEnum.DB_PARAMS_ERROR);

        updateProcessRequest.setUpdateTime(new Date());
        updateProcessRequest.setIsDeleted("N");

        TbProcessRequestExample example = new TbProcessRequestExample();
        example.createCriteria()
                .andRequestIdEqualTo(updateProcessRequest.getRequestId())
                .andPointIdEqualTo(curPointId)
                .andPointRunStatusEqualTo(PointRunStatusEnum.WAITING.getCode())
                .andIsDeletedEqualTo(CommonConstances.N);

        int result = tbProcessRequestMapper.updateByExampleSelective(updateProcessRequest, example);
        Assert.isTrue(result > 0, "数据库操作失败");
    }

    /**
     * 错误流程
     *
     * @param requestId 流程请求id
     */
    public void updateToError(String requestId) {
        BAssertUtil.notBlank(requestId, BErrorCodeEnum.DB_PARAMS_ERROR);

        TbProcessRequest updateProcessRequest = new TbProcessRequest();
        updateProcessRequest.setRequestId(requestId);
        updateProcessRequest.setPointRunStatus(PointRunStatusEnum.ERROR.getCode());
        updateProcessRequest.setUpdateTime(new Date());
        updateProcessRequest.setIsDeleted(CommonConstances.N);

        TbProcessRequestExample example = new TbProcessRequestExample();
        example.createCriteria()
                .andRequestIdEqualTo(requestId)
                .andPointRunStatusNotEqualTo(PointRunStatusEnum.FINISH.getCode())
                .andIsDeletedEqualTo(CommonConstances.N);

        int result = tbProcessRequestMapper.updateByExampleSelective(updateProcessRequest, example);
        Assert.isTrue(result > 0, "数据库操作失败");
    }

    /**
     * 恢复错误流程
     *
     * @param requestId 流程请求id
     */
    public void updateErrorToProcessing(String requestId) {
        BAssertUtil.notBlank(requestId, BErrorCodeEnum.DB_PARAMS_ERROR);

        TbProcessRequest updateProcessRequest = new TbProcessRequest();
        updateProcessRequest.setRequestId(requestId);
        updateProcessRequest.setPointRunStatus(PointRunStatusEnum.PROCESSING.getCode());
        updateProcessRequest.setUpdateTime(new Date());
        updateProcessRequest.setIsDeleted(CommonConstances.N);

        TbProcessRequestExample example = new TbProcessRequestExample();
        example.createCriteria()
                .andRequestIdEqualTo(requestId)
                .andPointRunStatusEqualTo(PointRunStatusEnum.ERROR.getCode())
                .andIsDeletedEqualTo(CommonConstances.N);

        int result = tbProcessRequestMapper.updateByExampleSelective(updateProcessRequest, example);
        Assert.isTrue(result > 0, "数据库操作失败");
    }

}
